using System;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;

using Microsoft.VisualStudio.TestTools.UnitTesting;
using Pegasus.Runtime.Remoting;

namespace Pegasus.UnitTests.Runtime.Remoting
{
    /// <summary>
    /// Class to test the remoting via the differnt channels and formatters
    /// </summary>
    [TestClass]
    public class RemoteChannelTest
    {
        // Local Instance Values
        private TestContext m_testContextInstance;

		/// <summary>
		/// Initializes a new instance of the <see cref="T:RemoteTcpChannelTest"/> class.
		/// </summary>
        public RemoteChannelTest()
		{
		}

		/// <summary>
		/// Gets or sets the test context which provides information about and 
		/// functionality for the current test run.
		/// </summary>
		/// <value>The test context.</value>
		public TestContext TestContext
		{
			get
			{
				return m_testContextInstance;
			}
			set
			{
				m_testContextInstance = value;
			}
		}

		/// <summary>
		/// Test the helpper channels with the given formatter
		/// </summary>
        [TestMethod]
        public void RemoteHelperTest()
        {
			// Put each test on a differnt port because the GC doesn't clean up the channels
			// fast enought and so a sencond test fails because someone is alrady bound to the port.
			int port = 8090;

			foreach( RemoteChannelType channelType in Enum.GetValues( typeof( RemoteChannelType ) ) )
			{
				foreach( RemoteFormatterType formatterType in Enum.GetValues( typeof( RemoteFormatterType ) ) )
				{
					TestChannel( channelType, formatterType, port );
					port++;
				}
			}
		}

        /// <summary>
        /// Tests the channel.
        /// </summary>
        /// <param name="channelType">Type of the channel.</param>
        /// <param name="formatterType">Type of the formatter.</param>
        /// <param name="port">The port.</param>
        public void TestChannel( RemoteChannelType channelType, RemoteFormatterType formatterType, int port )
        {
            string serverChannel = RemoteHelper.SetupAsServer( channelType, formatterType, port );
            Assert.IsFalse( string.IsNullOrEmpty( serverChannel ) );

            RemoteHelper.RegisterServerType( typeof( RemoteObject ), "RemoteObject", WellKnownObjectMode.Singleton );

            int clientPort = 0;
            if( channelType == RemoteChannelType.Ipc )
            {
                clientPort = port;
            }

            string clientChannel = RemoteHelper.SetupAsClient( channelType, formatterType, clientPort );
            Assert.IsFalse( string.IsNullOrEmpty( clientChannel ) );

            RemoteObject rObj = (RemoteObject) RemoteHelper.GetRemoteObject( channelType, "localhost", port, "RemoteObject" );

            // Test simple types
            int x = rObj.AddOne( 10 );
            Assert.IsTrue( x == 11 );

            // Test Strings
            string str = rObj.AppendStrings( "123456", "7890" );
            Assert.IsTrue( str == "1234567890" );

            // Test DateTime
            DateTime now = DateTime.Now;
            DateTime nextDay = rObj.AddOneDay( now );
            TimeSpan dateDiff = nextDay - now;
            Assert.IsTrue( dateDiff.Days == 1.0 );

            // Test Guid
            Guid guid = rObj.GetNewGuid();
            Assert.IsFalse( guid == Guid.Empty );

            RemoteCustomValueType valueType = rObj.GetCustomValueType( 10, "This is a test" );
            Assert.IsNotNull( valueType );
            Assert.IsTrue( valueType.Number == 10 );
            Assert.IsTrue( valueType.Name == "This is a test" );

			// TODO: need to support ObjRef in the return value of the XmlClientFormatterSink.
			if( formatterType != RemoteFormatterType.PegasusXml )
			{
				// Test secondary object references
				RemoteCustomRefType rRefObj = rObj.GetCustomRefType();

				// Test simple types
				x = rRefObj.AddOne( 20 );
				Assert.IsTrue( x == 21 );

				// Test Strings
				str = rRefObj.AppendStrings( "7890", "123456" );
				Assert.IsTrue( str == "7890123456" );
			}

            // Close down the channels
            RemoteHelper.ShutDownChannel( clientChannel );
            RemoteHelper.ShutDownChannel( serverChannel );

            // Make sure that all channels have closed
            Assert.IsTrue( ChannelServices.RegisteredChannels.Length == 0 );
        }
    }
}
